/**
  *16.3 单例类型
  * singleton type 是所有实例都可以有的。
  * 所有的对象实例都有一个 x.type 的单例类型，它只对应当前对象实例。这么做有什么意义呢？
  * 单例类型和单例对象不一样， 他是一种类型， 每一个引用 v 都有一个单例类型 v.type，
  * 他只有两个可能的值： v 和 null，他表示的时候当前对象的类型。
  * 单例类型用的最多的是在链式调用中，如下：
  */

import scala.reflect.runtime.universe._
class A {
  private var name:String = null
  def setName1(name:String)={
    this.name = name
    this // 返回调用对象
  }

  //这里需要注意的是，如上的A对象，这里的setName传入的是name名字，但是返回的千万要注意，是一个this.type
  def setName(name:String):this.type ={
    this.name = name
    this // 返回调用对象
  }

}
class B extends A{
  private var sex:String = null
  private var age:Int = 0

  def setSex(sex:String)={
    this.sex=sex
    this
  }

  def setAge(age:Int)={
    this.age=age

    /**
      * 必须引入 import scala.reflect.runtime.universe._
      * 才能用typeOf
      */
    println(typeOf[this.type])
    this
  }
}


val a:A = new A
val b:B = new B

/**
  * 这里链式调用就出错了，这是需要注意的地方，
  * 在scala中的单例类型为什么这里变红了？
  * 因为b执行完了之后scala认为返回的是类A的对象，
  * A里面是没有setAge的所以变红了
  */
b.setName1("WangBa").setAge(29)  // 无法执行
print(b)


/**
  * 下面的为什么没有变红呢？因为在下面是调用的setAge,是B自己的方法，
  * 所以返回的是B，然后B继承了A，所以有setName方法，所以成功了。
  * 处理这个问题的方法就是把刚才去掉的this.type加回来
  */
b.setName("WangBa").setAge(29)  // 可以执行
b.setAge(29).setName("WangBa")  // 可以执行

print(b)


